#pragma once

#include <string>
#include <list>
#include <vector>
#include <algorithm>
#include <sstream>

static std::string& operator-=(std::string& o1, std::string& o2)
{
	int i = o1.find(o2);
	o1.erase(i, o2.length());
	return o1;
};

class Dator
{
protected:
	Dator(){};
	Dator( Dator& o ){(*this) = o;};
	
	template<class T>
	T toVal(std::string &s)
	{
		std::stringstream str;
		str.unsetf(std::ios::skipws);
		str << s.c_str();
		T res;
		str >> res;
		return res;
	};
	template<>
	std::string toVal(std::string &s)
	{
		return s;
	};
public:
	virtual Dator& operator= (std::string& o) = 0;
	virtual Dator& operator+= (std::string& o) = 0;
	virtual Dator& operator-= (std::string& o) = 0;
	virtual bool operator== (std::string& o) = 0;
	virtual bool operator!= (std::string& o) = 0;

	virtual bool MultiValued() const = 0;
	virtual operator std::string() = 0;
};

template<class T>
class CDator : public Dator
{
public:
	CDator( T& t ) : m_data(t)
	{
	}

	Dator &operator= (std::string& input)
	{
		m_data = toVal<T>(input);
		return *this;
	}

	Dator &operator+= (std::string& input)
	{
		m_data += toVal<T>(input);
		return *this;
	}

	Dator &operator-= (std::string& input)
	{
		m_data -= toVal<T>(input);
		return *this;
	}

	bool operator== (std::string& o)
	{
		return o == (std::string)(*this);
	}

	bool operator!= (std::string& o)
	{
		return o != (std::string)(*this);
	}

	operator std::string()
	{
		return toString(m_data);
	}

	bool MultiValued() const
	{
		return false;
	}

protected:
	T& m_data;
	std::string toString(T &val)
	{
		std::stringstream str;
		str.unsetf(std::ios::skipws);
		str << val;
		std::string res;
		str >> res;
		return res;
	}
};



template<class T>
class CDatorList : public Dator
{
public:
	CDatorList(std::list<T> &v) : m_data(v)
	{ }
	Dator &operator =(std::string &s)
	{
		m_data.clear(); m_data.push_back(toVal<T>(s)); return *this;
	}
	Dator &operator +=(std::string &s)
	{
		m_data.push_back(toVal<T>(s)); return *this;
	}
	Dator &operator -=(std::string &s)
	{
		m_data.remove(toVal<T>(s)); return *this;
	}
	bool operator ==(std::string &s)
	{
		return (std::find(m_data.begin(),m_data.end(),toVal<T>(s))!=m_data.end());
	}
	bool operator !=(std::string &s)
	{
		return !((*this)==s);
	}
  
	operator std::string()
	{ 
		return toString(m_data.back()); 
	}

	operator std::list<T>&() 
	{
		return m_data; 
	}

	bool MultiValued() const 
	{
		return true;
	}
  
protected:
	std::list<T> &m_data;

	std::string toString(T &val)
	{
		std::stringstream str;
		str.unsetf(std::ios::skipws);
		str << val;
		std::string res;
		str >> res;
		return res;
	}
};

template<class T>
class CDatorVector : public Dator
{
public:
	CDatorVector(std::vector<T> &v) : m_data(v)
	{ }
	Dator &operator =(std::string &s)
	{
		m_data.clear();
		m_data.push_back(toVal<T>(s)); return *this;
	}
	Dator &operator +=(std::string &s)
	{
		m_data.push_back(toVal<T>(s));
		return *this;
	}
	Dator &operator -=(std::string &s)
	{
		std::remove(m_data.begin(), m_data.end(), toVal<T>(s));
		return *this;
	}
	bool operator ==(std::string &s)
	{
		return (std::find(m_data.begin(), m_data.end(), toVal<T>(s)) != m_data.end());
	}
	bool operator !=(std::string &s)
	{
		return !((*this)==s);
	}
  
	operator std::string()
	{ 
		return toString(m_data.back()); 
	}

	operator std::vector<T>&() 
	{
		return m_data; 
	}

	bool MultiValued() const 
	{
		return true;
	}
  
protected:
	std::vector<T> &m_data;

	std::string toString(T &val)
	{
		std::stringstream str;
		str.unsetf(std::ios::skipws);
		str << val;
		std::string res;
		str >> res;
		return res;
	}
};